package pl.makimo.fuzzy.linguistics;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pl.makimo.data.Combinations;
import pl.makimo.data.WeatherRecord;
import pl.makimo.fuzzy.norms.MinNorm;
import pl.makimo.fuzzy.norms.Norm;
import pl.makimo.fuzzy.norms.Type2Norm;
import pl.makimo.fuzzy.sets.CrispSet;

import com.csvreader.CsvWriter;

public class SummaryFactory {
	public static Map<String, Quantifier> quantifiers = new HashMap<String, Quantifier>();
	public static Map<String, LinguisticVariable> variables = new HashMap<String, LinguisticVariable>();
	
	public static Norm qualifiersNorm = new MinNorm();
	public static Norm summarizersNorm = new MinNorm();
	public static Norm type2qualifiersNorm = new Type2Norm();
	public static Norm type2summarizersNorm = new Type2Norm();
		
	public static List<String> qualifiers = new ArrayList<String>();
	public static List<String> summarizers = new ArrayList<String>();
	
	public static CrispSet<WeatherRecord> tuples = new CrispSet<WeatherRecord>();
	
	public static Object[][] results = new Object[0][];
	
	public static double weights[] = new double[11];
	
	public static void addQuantifier(Quantifier q) {
		quantifiers.put(q.label, q);
	}	
	
	public static void addVariable(LinguisticVariable var) {
		variables.put(var.name, var);
	}
	
	public static void clear() {
		quantifiers = new HashMap<String, Quantifier>();
		variables = new HashMap<String, LinguisticVariable>();
		
		qualifiersNorm = new MinNorm();
		summarizersNorm = new MinNorm();
		type2qualifiersNorm = new Type2Norm();
		type2summarizersNorm = new Type2Norm();
			
		qualifiers = new ArrayList<String>();
		summarizers = new ArrayList<String>();
		
		tuples = new CrispSet<WeatherRecord>();		
	}
	
	public static List<Summary> getSummaries() {
		/* Summarizers */
		List<Summarizer> usedSingleSummarizers = new ArrayList<Summarizer>();
		List<Summarizer> compoundSummarizers = new ArrayList<Summarizer>();
		
		for (String s : summarizers) {
			for (Object key : variables.get(s).labels.keySet()) {
				usedSingleSummarizers.add(Summarizer.fromLinguisticVariable(variables.get(s), (String)key));
			}
		}	
		
		for (int len = 1; len <= summarizers.size(); len++) {
			int[] indices;
			Combinations x = new Combinations(usedSingleSummarizers.size(), len);
			
			while (x.hasMore()) {
				indices = x.getNext();
				Summarizer<WeatherRecord> summarizer;
				
				summarizer = usedSingleSummarizers.get(indices[0]);
				
				for (int current = 1; current < indices.length; current++) {
					if (!summarizer.variable.equals(usedSingleSummarizers.get(indices[current]).variable)) {
						summarizer = new CompoundSummarizer(summarizer, usedSingleSummarizers.get(indices[current]), summarizersNorm, type2summarizersNorm);
					}
				}
				
				compoundSummarizers.add(summarizer);
			}				
		}
		
		/* Qualifiers */
		List<Qualifier> usedSingleQualifiers = new ArrayList<Qualifier>();
		List<Qualifier> compoundQualifiers = new ArrayList<Qualifier>();
		
		for (String s : qualifiers) {
			for (Object key : variables.get(s).labels.keySet()) {
				usedSingleQualifiers.add(Qualifier.fromLinguisticVariable(variables.get(s), (String)key));
			}
		}	
		
		for (int len = 1; len <= qualifiers.size(); len++) {
			int[] indices;
			Combinations x = new Combinations(usedSingleQualifiers.size(), len);
			
			while (x.hasMore()) {
				indices = x.getNext();
				Qualifier<WeatherRecord> qualifier;
				
				qualifier = usedSingleQualifiers.get(indices[0]);
				
				for (int current = 1; current < indices.length; current++) {
					qualifier = new CompoundQualifier(qualifier, usedSingleQualifiers.get(indices[current]), qualifiersNorm, type2qualifiersNorm);
				}
				
				compoundQualifiers.add(qualifier);
			}				
		}		
		
		List<Summary> summaries = new ArrayList<Summary>();
		
		for (Quantifier quantifier : quantifiers.values()) {
			for (Summarizer<WeatherRecord> summarizer : compoundSummarizers) {
				if (compoundQualifiers.size() > 0) {
					for (Qualifier<WeatherRecord> qualifier : compoundQualifiers) {
						try {
							summaries.add(new Summary<WeatherRecord>(quantifier, qualifier, summarizer, tuples, summarizersNorm, type2summarizersNorm));
						} catch (Exception e) {
						}	
					}
				} else {
					try {
						summaries.add(new Summary<WeatherRecord>(quantifier, summarizer, tuples, summarizersNorm, type2summarizersNorm));
					} catch (Exception e) {
					}	
				}
			}
		}
		
		return summaries;
	}
	
	public static void executeSummaries() {
		List<Summary> summaries = SummaryFactory.getSummaries();
		
		results = new Object[summaries.size()][];
		
		int i = 0;
		
		System.out.println("All summaries: " + summaries.size());
		
		for (Summary<WeatherRecord> summary : summaries) {
			System.out.println(summary.toString());
			
			double[] measures = new double[11];
			measures[0] = QualityMeasures.T1(summary);
			measures[1] = QualityMeasures.T2(summary);
			measures[2] = QualityMeasures.T3(summary);
			measures[3] = QualityMeasures.T4(summary);
			measures[4] = QualityMeasures.T5(summary);
			measures[5] = QualityMeasures.T6(summary);
			measures[6] = QualityMeasures.T7(summary);
			measures[7] = QualityMeasures.T8(summary);
			measures[8] = QualityMeasures.T9(summary);
			measures[9] = QualityMeasures.T10(summary);
			measures[10] = QualityMeasures.T11(summary);		
						
			results[i] = new Object[13];
			
			DecimalFormat df = new DecimalFormat("#.##");
			
			results[i][0] = summary.toString();
			results[i][1] = df.format(measures[0]);
			results[i][2] = df.format(measures[1]);
			results[i][3] = df.format(measures[2]);
			results[i][4] = df.format(measures[3]);
			results[i][5] = df.format(measures[4]);
			results[i][6] = df.format(measures[5]);
			results[i][7] = df.format(measures[6]);
			results[i][8] = df.format(measures[7]);
			results[i][9] = df.format(measures[8]);
			results[i][10] = df.format(measures[9]);
			results[i][11] = df.format(measures[10]);
			
			double weighted = 0.0;
			double weightsSum = 0.0;
			
			for (int j = 0; j < 11; j++) {
				weighted += weights[j] * measures[j];
				weightsSum += weights[j];
			}
			
			results[i][12] = df.format(weighted/weightsSum);
			
			/*
        	System.out.print(summary); System.out.print(";");
        	System.out.print(QualityMeasures.T1(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T2(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T3(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T4(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T5(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T6(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T7(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T8(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T9(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T10(summary)); System.out.print(";");
        	System.out.print(QualityMeasures.T11(summary)); System.out.print(";");
        	System.out.println();
        	*/
        	
        	i++;
    	}
	}
	
	public static void writeToFile(String filename) {
		CsvWriter writer = new CsvWriter(filename);
		
		for (int i = 0; i < results.length; i++) {
			String[] record = new String[13];
			
			for (int j = 0; j < 13; j++) {
				record[j] = results[i][j].toString();
			}
			
			System.out.print("Writing ");
			System.out.print(record);
			
			try {
				writer.writeRecord(record);
			} catch (IOException e) {
				e.printStackTrace();
				break;
			}
		}
		
		try {
			writer.flush();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
